package com.jerry.service.Impl;

import com.jerry.BO.ServerInfo;
import com.jerry.DTO.ServerInfoDTO;
import com.jerry.service.DiscoveryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DiscoveryServiceImpl implements DiscoveryService {
    private final Map<String, List<ServerInfo>> SERVER_MAP = new ConcurrentHashMap();

    @Override
    public void rigister(ServerInfoDTO serverInfo) {
        List<ServerInfo> serverInfos = SERVER_MAP.getOrDefault(serverInfo.getServerId(), new ArrayList<ServerInfo>());
        ServerInfo info = new ServerInfo();
        BeanUtils.copyProperties(serverInfo, info);
        info.setTimeStamp(System.currentTimeMillis());
        info.setAlive(true);
        if (!serverInfos.contains(info)) {
            serverInfos.add(info);
        }
        SERVER_MAP.put(serverInfo.getServerId(), serverInfos);
    }

    @Override
    public void heartbeat(ServerInfoDTO serverInfo) {
        List<ServerInfo> serverInfos = SERVER_MAP.getOrDefault(serverInfo.getServerId(), new ArrayList<>());
        boolean exists = false;
        for (ServerInfo server : serverInfos) {
            if (server.getHost().equals(serverInfo.getHost()) &&
                    server.getPort().equals(serverInfo.getPort())) {
                server.setTimeStamp(System.currentTimeMillis());
                server.setAlive(true);
                exists = true;
            }
        }
        if (!exists) {
            rigister(serverInfo);
        }
    }

    @Scheduled(cron = "*/10 * * * * *")
    public void checkIsAlive() {
        SERVER_MAP.forEach((serverid, serviceList) -> {
            List<ServerInfo> services = serviceList.stream()
                    .filter(serverInfo -> {
                        Long timeStamp = serverInfo.getTimeStamp() / 1000;
                        long current = System.currentTimeMillis() / 1000;
                        if (current - timeStamp > 30) {
                            serverInfo.setAlive(false);
                        }
                        return current - timeStamp < 60;
                    })
                    .collect(Collectors.toList());
            SERVER_MAP.put(serverid, services);
        });
        log.info("check server status end");
    }

    @Override
    public List<ServerInfo> aliveServers() {
        List<ServerInfo> chunkservers = SERVER_MAP.getOrDefault("chunk-server", new ArrayList<>());
        chunkservers.stream()
                    .filter(ServerInfo::isAlive)
                    .collect(Collectors.toList());
        return chunkservers;
    }

    @Override
    public Map<String, List<ServerInfo>> services() {
        return SERVER_MAP;
    }
}
